home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / topten.c < prev    next >
C/C++ Source or Header  |  1992-11-21  |  19KB  |  749 lines

  1. /*    SCCS Id: @(#)topten.c    3.1    92/11/20    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6.  
  7. #ifdef VMS
  8.  /* We don't want to rewrite the whole file, because that entails     */
  9.  /* creating a new version which requires that the old one be deletable. */
  10. # define UPDATE_RECORD_IN_PLACE
  11. #endif
  12.  
  13. /*
  14.  * Updating in place can leave junk at the end of the file in some
  15.  * circumstances (if it shrinks and the O.S. doesn't have a straightforward
  16.  * way to truncate it).  The trailing junk is harmless and the code
  17.  * which reads the scores will ignore it.
  18.  */
  19. #ifdef UPDATE_RECORD_IN_PLACE
  20. # ifndef SEEK_SET
  21. #  define SEEK_SET 0
  22. # endif
  23. static long final_fpos;
  24. #endif
  25.  
  26. #ifdef NO_SCAN_BRACK
  27. static void FDECL(nsb_mung_line,(char*));
  28. static void FDECL(nsb_unmung_line,(char*));
  29. #endif
  30.  
  31. #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
  32. #define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
  33. #define    NAMSZ    10
  34. #define    DTHSZ    60
  35. #define    PERSMAX     3        /* entries per name/uid per char. allowed */
  36. #define    POINTSMIN    1    /* must be > 0 */
  37. #define    ENTRYMAX    100    /* must be >= 10 */
  38.  
  39. #ifndef MICRO
  40. #define    PERS_IS_UID        /* delete for PERSMAX per name; now per uid */
  41. #endif
  42. struct toptenentry {
  43.     struct toptenentry *tt_next;
  44. #ifdef UPDATE_RECORD_IN_PLACE
  45.     long fpos;
  46. #endif
  47.     long points;
  48.     int deathdnum, deathlev;
  49.     int maxlvl,hp,maxhp;
  50.     int uid;
  51.     char plchar;
  52.     char sex;
  53.     char name[NAMSZ+1];
  54.     char death[DTHSZ+1];
  55.     char date[7];        /* yymmdd */
  56. } *tt_head;
  57.  
  58. static void NDECL(outheader);
  59. static int FDECL(outentry, (int,struct toptenentry *,int));
  60. static void FDECL(readentry, (FILE *,struct toptenentry *));
  61. static void FDECL(writeentry, (FILE *,struct toptenentry *));
  62. static int FDECL(classmon, (CHAR_P,BOOLEAN_P));
  63.  
  64. /* must fit with end.c */
  65. const char NEARDATA *killed_by_prefix[] = {
  66.     "killed by ", "choked on ", "poisoned by ", "", "drowned in ",
  67.     "", "crushed to death by ", "petrified by ", "",
  68.     "", "",
  69.     "", "", "" };
  70.  
  71. static void
  72. readentry(rfile,tt)
  73. FILE *rfile;
  74. struct toptenentry *tt;
  75. {
  76. #ifdef UPDATE_RECORD_IN_PLACE
  77.     /* note: fscanf() below must read the record's terminating newline */
  78.     final_fpos = tt->fpos = ftell(rfile);
  79. #endif
  80. #ifdef NO_SCAN_BRACK
  81.     if(fscanf(rfile,"%6s %d %d %d %d %d %d %ld%*c%c%c %s %s%*c",
  82. #  define TTFIELDS 13
  83. #else
  84.     if(fscanf(rfile, "%6s %d %d %d %d %d %d %ld %c%c %[^,],%[^\n]%*c",
  85. #  define TTFIELDS 12
  86. #endif
  87.             tt->date, &tt->uid,
  88.             &tt->deathdnum, &tt->deathlev,
  89.             &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->points,
  90.             &tt->plchar, &tt->sex,
  91. #ifdef LATTICE    /* return value is broken also, sigh */
  92.             tt->name, tt->death) < 1)
  93. #else
  94.             tt->name, tt->death) != TTFIELDS)
  95. #endif
  96. #undef TTFIELDS
  97.         tt->points = 0;
  98.     else {
  99. #ifdef NO_SCAN_BRACK
  100.         if(tt->points > 0) {
  101.             nsb_unmung_line(tt->name);
  102.             nsb_unmung_line(tt->death);
  103.         }
  104. #endif
  105.     }
  106. }
  107.  
  108. static void
  109. writeentry(rfile,tt)
  110. FILE *rfile;
  111. struct toptenentry *tt;
  112. {
  113. #ifdef NO_SCAN_BRACK
  114.     nsb_mung_line(tt->name);
  115.     nsb_mung_line(tt->death);
  116.     (void) fprintf(rfile,"%6s %d %d %d %d %d %d %ld %c%c %s %s\n",
  117. #else
  118.     (void) fprintf(rfile,"%6s %d %d %d %d %d %d %ld %c%c %s,%s\n",
  119. #endif
  120.         tt->date, tt->uid,
  121.         tt->deathdnum, tt->deathlev,
  122.         tt->maxlvl, tt->hp, tt->maxhp, tt->points,
  123.         tt->plchar, tt->sex,
  124.         onlyspace(tt->name) ? "_" : tt->name, tt->death);
  125. #ifdef NO_SCAN_BRACK
  126.     nsb_unmung_line(tt->name);
  127.     nsb_unmung_line(tt->death);
  128. #endif
  129. }
  130.  
  131. void
  132. topten(how)
  133. int how;
  134. {
  135.     int uid = getuid();
  136.     int rank, rank0 = -1, rank1 = 0;
  137.     int occ_cnt = PERSMAX;
  138.     register struct toptenentry *t0, *tprev;
  139.     struct toptenentry *t1;
  140.     FILE *rfile;
  141.     register int flg = 0;
  142. #ifdef LOGFILE
  143.     FILE *lfile;
  144. #endif /* LOGFILE */
  145.  
  146. #if defined(MICRO)
  147. #define HUP
  148. #else
  149. #define    HUP    if(!done_hup)
  150. #endif
  151.     /* create a new 'topten' entry */
  152.     t0 = newttentry();
  153.     /* deepest_lev_reached() is in terms of depth(), and reporting the
  154.      * deepest level reached in the dungeon death occurred in doesn't
  155.      * seem right, so we have to report the death level in depth() terms
  156.      * as well (which also seems reasonable since that's all the player
  157.      * sees on the screen anyway)
  158.      */
  159.     t0->deathdnum = u.uz.dnum;
  160.     t0->deathlev = depth(&u.uz);
  161.     t0->maxlvl = deepest_lev_reached(TRUE);
  162.     t0->hp = u.uhp;
  163.     t0->maxhp = u.uhpmax;
  164.     t0->points = u.urexp;
  165.     t0->plchar = pl_character[0];
  166.     t0->sex = (flags.female ? 'F' : 'M');
  167.     t0->uid = uid;
  168.     (void) strncpy(t0->name, plname, NAMSZ);
  169.     t0->name[NAMSZ] = '\0';
  170.     t0->death[0] = '\0';
  171.     switch (killer_format) {
  172.         default: impossible("bad killer format?");
  173.         case KILLED_BY_AN:
  174.             Strcat(t0->death, killed_by_prefix[how]);
  175.             (void) strncat(t0->death, an(killer), DTHSZ);
  176.             break;
  177.         case KILLED_BY:
  178.             Strcat(t0->death, killed_by_prefix[how]);
  179.             (void) strncat(t0->death, killer, DTHSZ);
  180.             break;
  181.         case NO_KILLER_PREFIX:
  182.             (void) strncat(t0->death, killer, DTHSZ);
  183.             break;
  184.     }
  185.     Strcpy(t0->date, get_date());
  186.     t0->tt_next = 0;
  187. #ifdef UPDATE_RECORD_IN_PLACE
  188.     t0->fpos = -1L;
  189. #endif
  190.  
  191. #ifdef LOGFILE        /* used for debugging (who dies of what, where) */
  192.     if (lock_file(LOGFILE, 10)) {
  193.         if(!(lfile = fopen_datafile(LOGFILE,"a"))) {
  194.         HUP raw_print("Cannot open log file!");
  195.         } else {
  196.         writeentry(lfile, t0);
  197.         (void) fclose(lfile);
  198.         }
  199.         unlock_file(LOGFILE);
  200.     }
  201. #endif /* LOGFILE */
  202.  
  203. #if defined(WIZARD) || defined(EXPLORE_MODE)
  204.     if (wizard || discover) {
  205.         raw_print("");
  206.         raw_printf(
  207.           "Since you were in %s mode, the score list will not be checked.",
  208.             wizard ? "wizard" : "discover");
  209.         return;
  210.     }
  211. #endif
  212.  
  213.     if (!lock_file(RECORD, 60)) return;
  214.  
  215. #ifdef UPDATE_RECORD_IN_PLACE
  216.     rfile = fopen_datafile(RECORD, "r+");
  217. #else
  218.     rfile = fopen_datafile(RECORD, "r");
  219. #endif
  220.  
  221.     if (!rfile) {
  222.         HUP raw_print("Cannot open record file!");
  223.         unlock_file(RECORD);
  224.         return;
  225.     }
  226.  
  227.     HUP raw_print("");
  228.  
  229.     /* assure minimum number of points */
  230.     if(t0->points < POINTSMIN) t0->points = 0;
  231.  
  232.     t1 = tt_head = newttentry();
  233.     tprev = 0;
  234.     /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
  235.     for(rank = 1; ; ) {
  236.         readentry(rfile, t1);
  237.         if (t1->points < POINTSMIN) t1->points = 0;
  238.         if(rank0 < 0 && t1->points < t0->points) {
  239.         rank0 = rank++;
  240.         if(tprev == 0)
  241.             tt_head = t0;
  242.         else
  243.             tprev->tt_next = t0;
  244.         t0->tt_next = t1;
  245. #ifdef UPDATE_RECORD_IN_PLACE
  246.         t0->fpos = t1->fpos;    /* insert here */
  247. #endif
  248.         occ_cnt--;
  249.         flg++;        /* ask for a rewrite */
  250.         } else tprev = t1;
  251.  
  252.         if(t1->points == 0) break;
  253.         if(
  254. #ifdef PERS_IS_UID
  255.         t1->uid == t0->uid &&
  256. #else
  257.         strncmp(t1->name, t0->name, NAMSZ) == 0 &&
  258. #endif
  259.         t1->plchar == t0->plchar && --occ_cnt <= 0) {
  260.             if(rank0 < 0) {
  261.             rank0 = 0;
  262.             rank1 = rank;
  263.             HUP {
  264.                 raw_printf(
  265.               "You didn't beat your previous score of %ld points.",
  266.                     t1->points);
  267.                 raw_print("");
  268.             }
  269.             }
  270.             if(occ_cnt < 0) {
  271.             flg++;
  272.             continue;
  273.             }
  274.         }
  275.         if(rank <= ENTRYMAX) {
  276.         t1 = t1->tt_next = newttentry();
  277.         rank++;
  278.         }
  279.         if(rank > ENTRYMAX) {
  280.         t1->points = 0;
  281.         break;
  282.         }
  283.     }
  284.     if(flg) {    /* rewrite record file */
  285. #ifdef UPDATE_RECORD_IN_PLACE
  286.         (void) fseek(rfile, (t0->fpos >= 0 ?
  287.                      t0->fpos : final_fpos), SEEK_SET);
  288. #else
  289.         (void) fclose(rfile);
  290.         if(!(rfile = fopen_datafile(RECORD,"w"))){
  291.             HUP raw_print("Cannot write record file");
  292.             unlock_file(RECORD);
  293.             return;
  294.         }
  295. #endif    /* UPDATE_RECORD_IN_PLACE */
  296.         if(!done_stopprint) if(rank0 > 0){
  297.             if(rank0 <= 10)
  298.             raw_print("You made the top ten list!");
  299.             else {
  300.             raw_printf(
  301.               "You reached the %d%s place on the top %d list.",
  302.                 rank0, ordin(rank0), ENTRYMAX);
  303.             }
  304.             raw_print("");
  305.         }
  306.     }
  307.     if(rank0 == 0) rank0 = rank1;
  308.     if(rank0 <= 0) rank0 = rank;
  309.     if(!done_stopprint) outheader();
  310.     t1 = tt_head;
  311.     for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
  312.         if(flg
  313. #ifdef UPDATE_RECORD_IN_PLACE
  314.             && rank >= rank0
  315. #endif
  316.         ) writeentry(rfile, t1);
  317.         if(done_stopprint) continue;
  318.         if(rank > flags.end_top &&
  319.           (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
  320.           && (!flags.end_own ||
  321. #ifdef PERS_IS_UID
  322.                   t1->uid != t0->uid
  323. #else
  324.                   strncmp(t1->name, t0->name, NAMSZ)
  325. #endif
  326.         )) continue;
  327.         if(rank == rank0-flags.end_around &&
  328.            rank0 > flags.end_top+flags.end_around+1 &&
  329.            !flags.end_own)
  330.           raw_print("");
  331.         if(rank != rank0)
  332.         (void) outentry(rank, t1, 0);
  333.         else if(!rank1)
  334.         (void) outentry(rank, t1, 1);
  335.         else {
  336.         int t0lth = outentry(0, t0, -1);
  337.         int t1lth = outentry(rank, t1, t0lth);
  338.         if(t1lth > t0lth) t0lth = t1lth;
  339.         (void) outentry(0, t0, t0lth);
  340.         }
  341.     }
  342.     if(rank0 >= rank) if(!done_stopprint)
  343.         (void) outentry(0, t0, 1);
  344. #ifdef UPDATE_RECORD_IN_PLACE
  345.     if (flg) {
  346. # ifdef TRUNCATE_FILE
  347.         /* if a reasonable way to truncate a file exists, use it */
  348.         truncate_file(rfile);
  349. # else
  350.         /* use sentinel record rather than relying on truncation */
  351.         t0->points = 0L;    /* terminates file when read back in */
  352.         t0->uid = t0->deathdnum = t0->deathlev = 0;
  353.         t0->maxlvl = t0->hp = t0->maxhp = 0;
  354.         t0->plchar = t0->sex = '-';
  355.         Strcpy(t0->name, "@");
  356.         Strcpy(t0->death, "<eod>\n");
  357.         writeentry(rfile, t0);
  358.         (void) fflush(rfile);
  359. # endif    /* TRUNCATE_FILE */
  360.     }
  361. #endif    /* UPDATE_RECORD_IN_PLACE */
  362.     (void) fclose(rfile);
  363.     unlock_file(RECORD);
  364. }
  365.  
  366. static void
  367. outheader() {
  368.     char linebuf[BUFSZ];
  369.     register char *bp;
  370.  
  371.     Strcpy(linebuf, " No  Points     Name");
  372.     bp = eos(linebuf);
  373.     while(bp < linebuf + COLNO - 9) *bp++ = ' ';
  374.     Strcpy(bp, "Hp [max]");
  375.     raw_print(linebuf);
  376. }
  377.  
  378. /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
  379. static int
  380. outentry(rank, t1, so)
  381. register struct toptenentry *t1;
  382. register int rank, so;
  383. {
  384.     register boolean second_line = TRUE;
  385.     char linebuf[BUFSZ], linebuf2[BUFSZ], linebuf3[BUFSZ], pbuf[BUFSZ];
  386.  
  387.     linebuf[0] = linebuf2[0] = linebuf3[0] = 0;
  388.     if(rank) Sprintf(eos(linebuf), "%3d", rank);
  389.     else Strcat(linebuf, "   ");
  390.  
  391.     Sprintf(eos(linebuf), " %10ld  %.10s", t1->points, t1->name);
  392.     Sprintf(eos(linebuf), "-%c ", t1->plchar);
  393.     if(!strncmp("escaped", t1->death, 7)) {
  394.       second_line = FALSE;
  395.       if(!strcmp(" (with the Amulet)", t1->death+7))
  396.         Strcat(linebuf, "escaped the dungeon with the Amulet");
  397.       else
  398.         Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
  399.           t1->maxlvl);
  400.     } else if(!strncmp("ascended", t1->death, 8)) {
  401.        Strcat(linebuf, "ascended to demigod");
  402.        if (t1->sex == 'F') Strcat(linebuf, "dess");
  403.        Strcat(linebuf, "-hood");
  404.        second_line = FALSE;
  405.     } else {
  406.       if(!strncmp(t1->death,"quit",4)) {
  407.         Strcat(linebuf, "quit");
  408.         second_line = FALSE;
  409.       } else if(!strncmp(t1->death,"starv",5)) {
  410.         Strcat(linebuf, "starved to death");
  411.         second_line = FALSE;
  412.       } else if(!strncmp(t1->death,"choked",6)) {
  413.         Sprintf(eos(linebuf), "choked on h%s food",
  414.             (t1->sex == 'F') ? "er" : "is");
  415.       } else if(!strncmp(t1->death,"poisoned",8)) {
  416.         Strcat(linebuf, "was poisoned");
  417.       } else if(!strncmp(t1->death,"crushed",7)) {
  418.         Strcat(linebuf, "was crushed to death");
  419.       } else if(!strncmp(t1->death, "petrified by ",13)) {
  420.         Strcat(linebuf, "turned to stone");
  421.       } else Strcat(linebuf, "died");
  422.  
  423.       if (t1->deathdnum == astral_level.dnum)
  424.         Strcpy(linebuf3, " in the endgame");
  425.       else
  426.         Sprintf(linebuf3, " in %s on level %d",
  427.             dungeons[t1->deathdnum].dname, t1->deathlev);
  428.       if(t1->deathlev != t1->maxlvl)
  429.         Sprintf(eos(linebuf3), " [max %d]", t1->maxlvl);
  430.       /* kludge for "quit while already on Charon's boat" */
  431.       if(!strncmp(t1->death, "quit ", 5))
  432.         Strcat(linebuf3, t1->death + 4);
  433.     }
  434.     Strcat(linebuf3, ".");
  435.  
  436.     if(t1->maxhp) {
  437.       register char *bp;
  438.       char hpbuf[10];
  439.       int hppos;
  440.       int lngr = strlen(linebuf) + strlen(linebuf3);
  441.       if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0';
  442.       else Sprintf(hpbuf, "%d", t1->hp);
  443.       hppos = COLNO - 7 - (int)strlen(hpbuf);
  444.       if (lngr >= hppos) {
  445.           if(so > 0) {
  446.           bp = eos(linebuf);
  447.           while(bp < linebuf + (COLNO-1)) *bp++ = ' ';
  448.           *bp = 0;
  449.           raw_print_bold(linebuf);
  450.           } else if(so == 0)
  451.           raw_print(linebuf);
  452.           Strcpy(linebuf, "               ");
  453.       }
  454.       Strcat(linebuf, linebuf3);
  455.       bp = eos(linebuf);
  456.  
  457.       if(bp <= linebuf + hppos) {
  458.         /* pad any necessary blanks to the hit point entry */
  459.         while(bp < linebuf + hppos) *bp++ = ' ';
  460.         Strcpy(bp, hpbuf);
  461.         if(t1->maxhp < 10)
  462.          Sprintf(eos(bp), "   [%d]", t1->maxhp);
  463.         else if(t1->maxhp < 100)
  464.          Sprintf(eos(bp), "  [%d]", t1->maxhp);
  465.         else Sprintf(eos(bp), " [%d]", t1->maxhp);
  466.       }
  467.     }
  468.  
  469. /*    Line 2 now contains the killer name */
  470.  
  471.     /* Quit, starved, ascended, and escaped contain no second line */
  472.     if (second_line) {
  473.         Strcpy(linebuf2, t1->death);
  474.         *linebuf2 = highc(*linebuf2);
  475.         Strcat(linebuf2, ".");
  476.     }
  477.  
  478.     if(so == 0) {
  479.         raw_print(linebuf);
  480.         if (second_line)
  481.         raw_printf("                %s", linebuf2);
  482.     } else if(so > 0) {
  483.       register char *bp = eos(linebuf);
  484.       if(so >= COLNO) so = COLNO-1;
  485.       while(bp < linebuf + so) *bp++ = ' ';
  486.       *bp = 0;
  487.       raw_print_bold(linebuf);
  488.       if(second_line) {
  489.           Sprintf(pbuf, "                %s", linebuf2);
  490.           raw_print_bold(pbuf);
  491.       }
  492.     }
  493.     return((int)strlen(linebuf)+(int)strlen(linebuf2));
  494. }
  495.  
  496. /*
  497.  * Called with args from main if argc >= 0. In this case, list scores as
  498.  * requested. Otherwise, find scores for the current player (and list them
  499.  * if argc == -1).
  500.  */
  501. void
  502. prscore(argc,argv)
  503. int argc;
  504. char **argv;
  505. {
  506.     const char **players;
  507.     int playerct;
  508.     int rank;
  509.     register struct toptenentry *t1, *t2;
  510.     FILE *rfile;
  511.     register int flg = 0, i;
  512.     char pbuf[BUFSZ];
  513. #ifdef nonsense
  514.     long total_score = 0L;
  515.     char totchars[10];
  516.     int totcharct = 0;
  517. #endif
  518.     int outflg = (argc >= -1);
  519. #ifdef PERS_IS_UID
  520.     int uid = -1;
  521. #else
  522.     const char *player0;
  523. #endif
  524.     rfile = fopen_datafile(RECORD, "r");
  525.     if (!rfile) {
  526.         raw_print("Cannot open record file!");
  527.         return;
  528.     }
  529.  
  530.     /* If the score list isn't after a game, we never went through */
  531.     /* init_dungeons() */
  532.     if (wiz1_level.dlevel == 0) init_dungeons();
  533.  
  534.     if(argc > 1 && !strncmp(argv[1], "-s", 2)){
  535.         if(!argv[1][2]){
  536.             argc--;
  537.             argv++;
  538.         } else if(!argv[1][3] && index(pl_classes, argv[1][2])) {
  539.             argv[1]++;
  540.             argv[1][0] = '-';
  541.         } else    argv[1] += 2;
  542.     }
  543.     if(argc <= 1){
  544. #ifdef PERS_IS_UID
  545.         uid = getuid();
  546.         playerct = 0;
  547. #  if defined(LINT) || defined(GCC_WARN)
  548.         players = 0;
  549. #  endif
  550. #else
  551.         player0 = plname;
  552.         if(!*player0)
  553.             player0 = "hackplayer";
  554.         playerct = 1;
  555.         players = &player0;
  556. #endif
  557.     } else {
  558.         playerct = --argc;
  559.         players = (const char **)++argv;
  560.     }
  561.     if(outflg) raw_print("");
  562.  
  563.     t1 = tt_head = newttentry();
  564.     for(rank = 1; ; rank++) {
  565.         readentry(rfile, t1);
  566.         if(t1->points == 0) break;
  567. #ifdef PERS_IS_UID
  568.         if(!playerct && t1->uid == uid)
  569.         flg++;
  570.         else
  571. #endif
  572.         for(i = 0; i < playerct; i++){
  573.         if(strcmp(players[i], "all") == 0 ||
  574.            strncmp(t1->name, players[i], NAMSZ) == 0 ||
  575.           (players[i][0] == '-' &&
  576.            players[i][1] == t1->plchar &&
  577.            players[i][2] == 0) ||
  578.           (digit(players[i][0]) && rank <= atoi(players[i])))
  579.             flg++;
  580.         }
  581.         t1 = t1->tt_next = newttentry();
  582.     }
  583.     (void) fclose(rfile);
  584.     if(!flg) {
  585.         if(outflg) {
  586.         Strcpy(pbuf, "Cannot find any entries for ");
  587.         if(playerct < 1) Strcat(pbuf, "you.");
  588.         else {
  589.           if(playerct > 1) Strcat(pbuf, "any of ");
  590.           for(i=0; i<playerct; i++) {
  591.               Strcat(pbuf, players[i]);
  592.               if(i<playerct-1) Strcat(pbuf, ":");
  593.           }
  594.           raw_print(pbuf);
  595.           raw_printf("Call is: %s -s [-role] [maxrank] [playernames]",
  596.                  hname);
  597.         }
  598.         }
  599.         return;
  600.     }
  601.  
  602.     if(outflg) outheader();
  603.     t1 = tt_head;
  604.     for(rank = 1; t1->points != 0; rank++, t1 = t2) {
  605.         t2 = t1->tt_next;
  606. #ifdef PERS_IS_UID
  607.         if(!playerct && t1->uid == uid)
  608.             goto outwithit;
  609.         else
  610. #endif
  611.         for(i = 0; i < playerct; i++){
  612.             if(strcmp(players[i], "all") == 0 ||
  613.                strncmp(t1->name, players[i], NAMSZ) == 0 ||
  614.               (players[i][0] == '-' &&
  615.                players[i][1] == t1->plchar &&
  616.                players[i][2] == 0) ||
  617.               (digit(players[i][0]) && rank <= atoi(players[i]))){
  618. #ifdef PERS_IS_UID
  619.             outwithit:
  620. #endif
  621.                 if(outflg)
  622.                     (void) outentry(rank, t1, 0);
  623. #ifdef nonsense
  624.                 total_score += t1->points;
  625.                 if(totcharct < sizeof(totchars)-1)
  626.                     totchars[totcharct++] = t1->plchar;
  627. #endif
  628.                 break;
  629.             }
  630.         }
  631.         dealloc_ttentry(t1);
  632.     }
  633. #ifdef nonsense
  634.     totchars[totcharct] = 0;
  635.  
  636.     /* We would like to determine whether you're experienced.  However,
  637.        the information collected here only tells about the scores/roles
  638.        that got into the topten (top 100?).  We should maintain a
  639.        .hacklog or something in his home directory. */
  640.     flags.beginner = (total_score < 6000);
  641.     for(i=0; i<6; i++)
  642.         if(!index(totchars, pl_classes[i])) {
  643.         flags.beginner = 1;
  644.         if(!pl_character[0]) pl_character[0] = pl_classes[i];
  645.         break;
  646.     }
  647. #endif /* nonsense /**/
  648. }
  649.  
  650. static int
  651. classmon(plch, fem)
  652. char plch;
  653. boolean fem;
  654. {
  655.     switch (plch) {
  656.         case 'A': return PM_ARCHEOLOGIST;
  657.         case 'B': return PM_BARBARIAN;
  658.         case 'C': return (fem ? PM_CAVEWOMAN : PM_CAVEMAN);
  659.         case 'E': return PM_ELF;
  660.         case 'H': return PM_HEALER;
  661.         case 'F':    /* accept old Fighter class */
  662.         case 'K': return PM_KNIGHT;
  663.         case 'P': return (fem ? PM_PRIESTESS : PM_PRIEST);
  664.         case 'R': return PM_ROGUE;
  665.         case 'N':    /* accept old Ninja class */
  666.         case 'S': return PM_SAMURAI;
  667. #ifdef TOURIST
  668.         case 'T': return PM_TOURIST;
  669. #else
  670.         case 'T': return PM_HUMAN;
  671. #endif
  672.         case 'V': return PM_VALKYRIE;
  673.         case 'W': return PM_WIZARD;
  674.         default: impossible("What weird class is this? (%c)", plch);
  675.             return PM_HUMAN_ZOMBIE;
  676.     }
  677. }
  678.  
  679. /*
  680.  * Get a random player name and class from the high score list,
  681.  * and attach them to an object (for statues or morgue corpses).
  682.  */
  683. struct obj *
  684. tt_oname(otmp)
  685. struct obj *otmp;
  686. {
  687.     int rank;
  688.     register int i;
  689.     register struct toptenentry *tt;
  690.     FILE *rfile;
  691.  
  692.     if (!otmp) return((struct obj *) 0);
  693.  
  694.     rfile = fopen_datafile(RECORD, "r");
  695.     if (!rfile) {
  696.         panic("Cannot open record file!");
  697.     }
  698.  
  699.     tt = newttentry();
  700.     rank = rnd(10);
  701. pickentry:
  702.     for(i = rank; i; i--) {
  703.         readentry(rfile, tt);
  704.         if(tt->points == 0) break;
  705.     }
  706.  
  707.     if(tt->points == 0) {
  708.         if(rank > 1) {
  709.             rank = 1;
  710.             rewind(rfile);
  711.             goto pickentry;
  712.         }
  713.         dealloc_ttentry(tt);
  714.         otmp = (struct obj *) 0;
  715.     } else {
  716.         otmp->corpsenm = classmon(tt->plchar, (tt->sex == 'F'));
  717.         otmp->owt = weight(otmp);
  718.         /* Note: oname() is safe since otmp is first in chains */
  719.         otmp = oname(otmp, tt->name, 0);
  720.         fobj = otmp;
  721.         level.objects[otmp->ox][otmp->oy] = otmp;
  722.         dealloc_ttentry(tt);
  723.     }
  724.  
  725.     (void) fclose(rfile);
  726.     return otmp;
  727. }
  728.  
  729. #ifdef NO_SCAN_BRACK
  730. /* Lattice scanf isn't up to reading the scorefile.  What */
  731. /* follows deals with that; I admit it's ugly. (KL) */
  732. /* Now generally available (KL) */
  733. static void
  734. nsb_mung_line(p)
  735.     char *p;
  736.     {
  737.     while(p=index(p,' '))*p='|';
  738. }
  739.  
  740. static void
  741. nsb_unmung_line(p)
  742.     char *p;
  743.     {
  744.     while(p=index(p,'|'))*p=' ';
  745. }
  746. #endif
  747.  
  748. /*topten.c*/
  749.